/**
 * Copyright (c) Software Institude of PKU
 * All rights reserved. 
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 */
package edu.pku.sei.modeler.model.uml.Kernel;
// imports:
import org.w3c.dom.Element;

import edu.pku.sei.gefcommon.descriptor.annotation.EnumerationProperty;
import edu.pku.sei.gefcommon.descriptor.annotation.MethodProperty;
import edu.pku.sei.modeler.model.common.MetaTypedList;
import edu.pku.sei.modeler.model.uml.InternalStructures.ConnectorEnd;
import edu.pku.sei.modeler.model.uml.Nodes.Deployment;
import edu.pku.sei.modeler.model.xml.XMLUtility;
import edu.pku.sei.modeler.uml.modelHelper.ModelPackage;
import edu.pku.sei.modeler.uml.util.MetaTypedSet;


/**
 * @generated
 *
 */
public class Property extends StructuralFeature implements IProperty {
	// attributes
	
	protected boolean isDerived;
	
	protected boolean isDerivedUnion;
	
	protected String defaultLiteral;
	
	protected AggregationKind aggregation = AggregationKind.none;
	
	protected boolean isComposite;
	
	
	
	
	// references
	
	protected MetaTypedList subsettedProperty;
	
	protected MetaTypedList redefinedProperty;
	
	protected MetaTypedList opposite;
	
	protected MetaTypedList association;
	
	protected MetaTypedList defaultValue;
	
	
	
	protected MetaTypedList end;
	
	protected MetaTypedList deployedElement;
	
	protected MetaTypedList deployment;
	
	// getters & setters for attributes
	
//	 added by zsj
	/**
	 * 
	 */
	public final static String UNDEFINED_TYPE_NAME = "<Undefined>";

	/**
	 * 
	 */
	protected final static String PUBLIC_STRING = "+";

	/**
	 * 
	 */
	protected final static String PROTECTED_STRING = "#";

	/**
	 * 
	 */
	protected final static String PRIVATE_STRING = "-";

	/**
	 * 
	 */
	protected final static String PACKAGE_STRING = "~";
	
	//end of adding
	
	//added by zsj
	public Property() {
		this.setVisibility(VisibilityKind.PRIVATE);
		this.setLower(1);
		this.setUpper(1);
	}
	
	
	
	@MethodProperty(
			id = "PROPERTY_ISDERIVED",
			catalog = "Other",
			name = ModelPackage.PROPERTY_ISDERIVED,
			setter = "setIsDerived"
			)
	
	public boolean getIsDerived() {
		return isDerived;
	}
	public void setIsDerived(boolean newIsDerived) {
		boolean oldisDerived = isDerived;
		isDerived = newIsDerived;
//		firePropertyChange(ModelPackage.PROPERTY_ISDERIVED, oldisDerived, newIsDerived);
		if(getContainer() != null)
			getContainer().firePropertyChange(ModelPackage.PROPERTY_ISDERIVED, oldisDerived, newIsDerived);
	}
	
	@MethodProperty(
			id = "PROPERTY_ISDERIVEDUNION",
			catalog = "Other",
			name = ModelPackage.PROPERTY_ISDERIVEDUNION,
			setter = "setIsDerivedUnion"
			)
	
	public boolean getIsDerivedUnion() {
		return isDerivedUnion;
	}
	public void setIsDerivedUnion(boolean newIsDerivedUnion) {
		boolean oldisDerivedUnion = isDerivedUnion;
		isDerivedUnion = newIsDerivedUnion;
		if(getContainer() != null)
			getContainer().firePropertyChange(ModelPackage.PROPERTY_ISDERIVEDUNION, oldisDerivedUnion, newIsDerivedUnion);
	}
	
	@MethodProperty(
			id = "PROPERTY_DEFAULTLITERAL",
			catalog = "General",
			name = ModelPackage.PROPERTY_DEFAULTLITERAL,
			setter = "setDefaultLiteral"
			)
	
	public String getDefaultLiteral() {
		return defaultLiteral;
	}
	public void setDefaultLiteral(String newDefaultLiteral) {
		String olddefaultLiteral = defaultLiteral;
		defaultLiteral = newDefaultLiteral;
		if(getContainer() != null)
			getContainer().firePropertyChange(ModelPackage.PROPERTY_DEFAULTLITERAL, olddefaultLiteral, newDefaultLiteral);
	}
	@MethodProperty(id = "PROPERTY_AGGREGATION", catalog = "Other", name = ModelPackage.PROPERTY_AGGREGATION, setter = "setAggregation")
	@EnumerationProperty(function = "getAllAggregationKinds")
	public AggregationKind getAggregation() {
		return aggregation;
	}
	public void setAggregation(AggregationKind newAggregation) {
		AggregationKind oldaggregation = aggregation;
		aggregation = newAggregation;
		if(getContainer() != null)
			getContainer().firePropertyChange(ModelPackage.PROPERTY_AGGREGATION, oldaggregation, newAggregation);
	}
	public Object[] getAllAggregationKinds() {
		return AggregationKind.getAllAggregationKinds();
	}
//	@MethodProperty(
//			id = "PROPERTY_ISCOMPOSITE",
//			catalog = "Model",
//			name = ModelPackage.PROPERTY_ISCOMPOSITE,
//			setter = "setisComposite"
//			)
	
	public boolean getIsComposite() {
		return isComposite;
	}
	public void setIsComposite(boolean newIsComposite) {
		boolean oldisComposite = isComposite;
		isComposite = newIsComposite;
		if(getContainer() != null)
			getContainer().firePropertyChange(ModelPackage.PROPERTY_ISCOMPOSITE, oldisComposite, newIsComposite);
	}
	
	// getters for references
	
	public MetaTypedList getSubsettedProperty() {
		if(subsettedProperty == null) {
			subsettedProperty = new MetaTypedSet(Property.class, this, ModelPackage.PROPERTY_SUBSETTEDPROPERTY);
		}
		return subsettedProperty;
	}
	
	public MetaTypedList getRedefinedProperty() {
		if(redefinedProperty == null) {
			redefinedProperty = new MetaTypedSet(Property.class, this, ModelPackage.PROPERTY_REDEFINEDPROPERTY);
		}
		return redefinedProperty;
	}
	
	public MetaTypedList getOpposite() {
		if(opposite == null) {
			opposite = new MetaTypedSet(Property.class, this, ModelPackage.PROPERTY_OPPOSITE);
		}
		return opposite;
	}
	
	public MetaTypedList getAssociation() {
		if(association == null) {
			association = new MetaTypedSet(Association.class, this, ModelPackage.PROPERTY_ASSOCIATION);
		}
		return association;
	}
	
	public MetaTypedList getDefaultValue() {
		if(defaultValue == null) {
			defaultValue = new MetaTypedSet(ValueSpecification.class, this, ModelPackage.PROPERTY_DEFAULTVALUE);
		}
		return defaultValue;
	}
	
	public MetaTypedList getEnd() {
		if(end == null) {
			end = new MetaTypedSet(ConnectorEnd.class, this, ModelPackage.CONNECTABLEELEMENT_END);
		}
		return end;
	}
	
	public MetaTypedList getDeployedElement() {
		if(deployedElement == null) {
			deployedElement = new MetaTypedSet(PackageableElement.class, this, ModelPackage.DEPLOYMENTTARGET_DEPLOYEDELEMENT);
		}
		return deployedElement;
	}
	
	public MetaTypedList getDeployment() {
		if(deployment == null) {
			deployment = new MetaTypedSet(Deployment.class, this, ModelPackage.DEPLOYMENTTARGET_DEPLOYMENT);
		}
		return deployment;
	}
	
	// save & load
	public void serialize(Element root) {
		super.serialize(root);
		// attributes
		
		XMLUtility.xmlInstance.serializeAttribute(root, ModelPackage.PROPERTY_ISDERIVED, isDerived);
		
		XMLUtility.xmlInstance.serializeAttribute(root, ModelPackage.PROPERTY_ISDERIVEDUNION, isDerivedUnion);
		
		XMLUtility.xmlInstance.serializeAttribute(root, ModelPackage.PROPERTY_DEFAULTLITERAL, defaultLiteral);
		
//		XMLUtility.xmlInstance.serializeNode(root, ModelPackage.PROPERTY_AGGREGATION, aggregation);
		
		XMLUtility.xmlInstance.serializeAttribute(root, ModelPackage.PROPERTY_ISCOMPOSITE, isComposite);
		
		// references
		
		XMLUtility.xmlInstance.serializeNodesNotContain(root, ModelPackage.PROPERTY_SUBSETTEDPROPERTY, subsettedProperty);		
		
		XMLUtility.xmlInstance.serializeNodesNotContain(root, ModelPackage.PROPERTY_REDEFINEDPROPERTY, redefinedProperty);		
		
		XMLUtility.xmlInstance.serializeNodesNotContain(root, ModelPackage.PROPERTY_OPPOSITE, opposite);		
		
		XMLUtility.xmlInstance.serializeNodes(root, ModelPackage.PROPERTY_ASSOCIATION, association);		
		if (this.aggregation != null) {
			XMLUtility.xmlInstance.serializeAttribute(root, ModelPackage.PROPERTY_AGGREGATION, this.aggregation.getEnumName());
		}

		
		
		XMLUtility.xmlInstance.serializeNodes(root, ModelPackage.PROPERTY_DEFAULTVALUE, defaultValue);
		
		XMLUtility.xmlInstance.serializeNodesNotContain(root, ModelPackage.CONNECTABLEELEMENT_END, end);		
		
		XMLUtility.xmlInstance.serializeNodesNotContain(root, ModelPackage.DEPLOYMENTTARGET_DEPLOYEDELEMENT, deployedElement);		
		
		XMLUtility.xmlInstance.serializeNodes(root, ModelPackage.DEPLOYMENTTARGET_DEPLOYMENT, deployment);
		
	}
	
	public void deSerialize(Element root) {
		super.deSerialize(root);
		// attributes
		
		isDerived = XMLUtility.xmlInstance.deSerializeBoolean(root, ModelPackage.PROPERTY_ISDERIVED);
		
		isDerivedUnion = XMLUtility.xmlInstance.deSerializeBoolean(root, ModelPackage.PROPERTY_ISDERIVEDUNION);
		
		defaultLiteral = XMLUtility.xmlInstance.deSerializeString(root, ModelPackage.PROPERTY_DEFAULTLITERAL);
		
		//aggregation = (AggregationKind)XMLUtility.xmlInstance.deSerializeNode(root, ModelPackage.PROPERTY_AGGREGATION, this);
		aggregation = new AggregationKind(XMLUtility.xmlInstance.deSerializeString(root, ModelPackage.PROPERTY_AGGREGATION));
		
		isComposite = XMLUtility.xmlInstance.deSerializeBoolean(root, ModelPackage.PROPERTY_ISCOMPOSITE);
		
		// references
		
		this.getSubsettedProperty().addAll(XMLUtility.xmlInstance.deSerializeNodesNotContain(root, ModelPackage.PROPERTY_SUBSETTEDPROPERTY, this));
		
		this.getRedefinedProperty().addAll(XMLUtility.xmlInstance.deSerializeNodesNotContain(root, ModelPackage.PROPERTY_REDEFINEDPROPERTY, this));
		
		this.getOpposite().addAll(XMLUtility.xmlInstance.deSerializeNodesNotContain(root, ModelPackage.PROPERTY_OPPOSITE, this));
		
		this.getAssociation().addAll(XMLUtility.xmlInstance.deSerializeNodes(root, ModelPackage.PROPERTY_ASSOCIATION));
		
		this.getDefaultValue().addAll(XMLUtility.xmlInstance.deSerializeNodes(root, ModelPackage.PROPERTY_DEFAULTVALUE));
		
		this.getEnd().addAll(XMLUtility.xmlInstance.deSerializeNodesNotContain(root, ModelPackage.CONNECTABLEELEMENT_END, this));
		
		this.getDeployedElement().addAll(XMLUtility.xmlInstance.deSerializeNodesNotContain(root, ModelPackage.DEPLOYMENTTARGET_DEPLOYEDELEMENT, this));
		
		this.getDeployment().addAll(XMLUtility.xmlInstance.deSerializeNodes(root, ModelPackage.DEPLOYMENTTARGET_DEPLOYMENT));
		
	}
	
	public void dynamicSet(String featureID, Object value) {
		if(featureID == null || "".equals(featureID)) {
			return;
		}
		// attributes
		
		else if(ModelPackage.PROPERTY_AGGREGATION.equals(featureID)) {
			aggregation = (AggregationKind)value;
		}
		
		// references
		
		else if(ModelPackage.PROPERTY_SUBSETTEDPROPERTY.equals(featureID)) {
			getSubsettedProperty().add(value);
		}
		
		else if(ModelPackage.PROPERTY_REDEFINEDPROPERTY.equals(featureID)) {
			getRedefinedProperty().add(value);
		}
		
		else if(ModelPackage.PROPERTY_OPPOSITE.equals(featureID)) {
			getOpposite().add(value);
		}
		
		else if(ModelPackage.PROPERTY_ASSOCIATION.equals(featureID)) {
			getAssociation().add(value);
		}
		
		else if(ModelPackage.CONNECTABLEELEMENT_END.equals(featureID)) {
			getEnd().add(value);
		}
		
		else if(ModelPackage.DEPLOYMENTTARGET_DEPLOYEDELEMENT.equals(featureID)) {
			getDeployedElement().add(value);
		}
		
		else
			super.dynamicSet(featureID, value);
	}
	
	/**
	 * return the custom label of the property, given UML2 specification and a
	 * custom style.
	 * 
	 * @param style
	 *            the integer representing the style of the label
	 * 
	 * @return the string corresponding to the label of the property
	 */
	public String getCustomLabel() {
		StringBuffer buffer = new StringBuffer();
		// visibility

		buffer.append(" ");
		buffer.append(this.getVisibilityAsSign());

		// derived property
		if (this.getIsDerived()) {
			buffer.append("/");
		}
		// name
		buffer.append(" ");
		buffer.append(this.getName());

		// type
		if (this.getTypeAsClassifier() != null) {
			buffer.append(": " + this.getTypeAsClassifier().getName());
		} else {
			buffer.append(": " + UNDEFINED_TYPE_NAME);
		}

		// multiplicity -> do not display [1]
		String multiplicity = this.getMultiplicityAsString();
		// if(!multiplicity.trim().equals("[1]")) {
		buffer.append(multiplicity);
		// }

		// default value
		if ((this.getDefaultLiteral() != null) && this.getDefaultLiteral().length() != 0) {
			buffer.append(" = ");
			buffer.append(this.getDefaultLiteral());
		}

		// TODO property modifiers
		// String modifiers = this.getModifiersAsString(multiLine);
		// if (!modifiers.equals("")) {
		// // if(multiLine) {
		// // buffer.append("\n");
		// // }
		// buffer.append(" {");
		// buffer.append(modifiers);
		// buffer.append("}");
		// }
		return buffer.toString();
	}

	/**
	 * Return the multiplicity of the element "[x..y]"
	 * 
	 * @return the string representing the multiplicity
	 */
	public String getMultiplicityAsString() {
		if (getLower() == 1 && getLower() == getUpper()) {
			return "";
		}
		
		
		StringBuffer buffer = new StringBuffer();
		buffer.append(" [");
		buffer.append(getMultiplicityAsStringWithoutSquareBrackets());
		buffer.append("]");
		return buffer.toString();
	}

	/**
	 * Returns the String corresponding to the multiplicity without square
	 * brackets
	 * 
	 * @return the string representing the multiplicity, without square brackets
	 */
	public String getMultiplicityAsStringWithoutSquareBrackets() {
		StringBuffer buffer = new StringBuffer();
		// special case for [1] and [*]
		int lower = this.getLower();
		int upper = this.getUpper();

		if (lower == upper) {
			buffer.append(lower);
		} else if ((lower == 0) && (upper == -1)) {
			buffer.append("*");
		} else if (upper == -1) {
			buffer.append(lower);
			buffer.append("..*");
		} else {
			buffer.append(lower);
			buffer.append("..");
			buffer.append(upper);
		}
		return buffer.toString();
	}

	/**
	 * Returns the modifier of the property, separated by a comma, as as single
	 * line if <code>multiline</code> is <code>false</code> or as a
	 * multiline string if <code>multiline</code> is <code>false</code>.
	 * 
	 * @param multiLine
	 *            boolean that indiacates if the string should have several
	 *            lines when set to <code>true</code> or only one line when
	 *            set to <code>false</code>.
	 * 
	 * @return a string giving all modifiers for the property
	 */
	public String getModifiersAsString(boolean multiLine) {
		StringBuffer buffer = new StringBuffer();
		boolean needsComma = false;
		String NL = (multiLine) ? "\n" : "";

		// Return property modifiers
		if (getIsReadOnly()) {
			buffer.append("readOnly");
			needsComma = true;
		}
		if (getIsDerivedUnion()) {
			if (needsComma) {
				buffer.append(",");
				buffer.append(NL);
			}
			buffer.append("union");
			needsComma = true;
		}
		if (getIsOrdered()) {
			if (needsComma) {
				buffer.append(",");
				buffer.append(NL);
			}
			buffer.append("ordered");
			needsComma = true;
		}
		if (getIsUnique()) {
			if (needsComma) {
				buffer.append(",");
				buffer.append(NL);
			}
			buffer.append("unique");
			needsComma = true;
		}

		// TODO
		// is the property redefining another property ?
		// Iterator<Property> it = this.getRedefinedProperties().iterator();
		// while (it.hasNext()) {
		// org.eclipse.uml2.uml.Property property = it.next();
		// if(needsComma) {
		// buffer.append(",");
		// buffer.append(NL);
		// }
		// buffer.append("redefines ");
		// buffer.append(property.getName());
		// needsComma = true;
		// }
		//
		// // is the property subsetting another property ?
		// Iterator<org.eclipse.uml2.uml.Property> it2 =
		// uml2Property.getSubsettedProperties().iterator();
		// while (it2.hasNext()) {
		// org.eclipse.uml2.uml.Property property = it2.next();
		// if(needsComma) {
		// buffer.append(",");
		// buffer.append(NL);
		// }
		// buffer.append("subsets ");
		// buffer.append(property.getName());
		// needsComma = true;
		// }

		return buffer.toString();
	}

	public String getVisibilityAsSign() {
		String vKindValue = "";

		VisibilityKind kind = this.getVisibility();
		
		/*
		 * to avoid null type of visibility
		 */
		if (VisibilityKind.PUBLIC.equals(kind)) {
			vKindValue = "+";
		}
		else if (VisibilityKind.PRIVATE.equals(kind)) {
			vKindValue = "-";
		}
		else if (VisibilityKind.PROTECTED.equals(kind)) {
			vKindValue = "#";
		}
		else if (VisibilityKind.PACKAGE.equals(kind)) {
			vKindValue = "~";
		}
		return vKindValue;
		
//		if (kind.equals(VisibilityKind.PUBLIC)) {
//			vKindValue = "+";
//		} else if (kind.equals(VisibilityKind.PRIVATE)) {
//			vKindValue = "-";
//		} else if (kind.equals(VisibilityKind.PACKAGE)) {
//			vKindValue = "~";
//		} else if (kind.equals(VisibilityKind.PROTECTED)) {
//			vKindValue = "#";
//		}
//		return vKindValue;
	}
	
	@Override
	public void setName(String name){
		String oldName = getName();
		super.setName(name);
		if (getContainer()!=null)
			getContainer().firePropertyChange(ModelPackage.NAMEDELEMENT_NAME, oldName, name);
	}
}
 
 
 
 
 